package cn.t.facade.device;


import cn.t.constants.CommonConstants;
import cn.t.converter.device.DeviceOpenRecordDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.PageInfoDTO;
import cn.t.core.mode.PageQueryDTO;
import cn.t.dto.device.DeviceOpenRecordDTO;
import cn.t.dto.device.vo.OpenCloseDTO;
import cn.t.enums.order.ErrorEnum;
import cn.t.model.common.MailDO;
import cn.t.model.device.DeviceDO;
import cn.t.model.device.DeviceOpenRecordDO;
import cn.t.request.OpenRecordReq;
import cn.t.service.device.DeviceOpenRecordService;
import cn.t.service.device.DeviceService;
import cn.t.service.user.CustomerFirmService;
import cn.t.utils.DateUtil;
import cn.t.utils.ExcelUtil;
import cn.t.vo.order.OpenRecordVO;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 设备开门记录表(DeviceOpenRecord)服务编排
 *
 * @author t
 * @since 2024-05-24 10:19:34
 */
@Slf4j
@Service
@AllArgsConstructor
public class DeviceOpenRecordFacade extends FacadeImpl<DeviceOpenRecordDTO, DeviceOpenRecordDO, DeviceOpenRecordDTOConverter, DeviceOpenRecordService> {

    private final DeviceService deviceService;
    private final CustomerFirmService customerFirmService;


    public List<DeviceOpenRecordDTO> getDeviceOpenRecordList(List<String> orderSn) {
        return converter.do2DtoList(service.getDeviceOpenRecordByOrderSn(orderSn));
    }

    public PageInfoDTO<OpenRecordVO> openRecordPage(PageQueryDTO<OpenRecordReq> request) {
        DeviceOpenRecordDO queryParams = this.converter.req2Do(request.getParam());
        List<DeviceOpenRecordDO> openRecordDOS = getDeviceOpenRecords(request.getParam(), queryParams, request.getStart(), request.getPageSize());
        long total = this.service.count(queryParams);

        List<OpenRecordVO> records = openRecordDOS.stream().map(f -> this.converter.do2OpenRecordVo(f)).collect(Collectors.toList());
        return new PageInfoDTO<>(request.getPageNo(), request.getPageSize(), total, records);
    }

    private List<DeviceOpenRecordDO> getDeviceOpenRecords(OpenRecordReq req, DeviceOpenRecordDO queryParams, Integer start, Integer pageSize) {
        // 根据设备名称模糊查询设备id
        if (StringUtils.hasText(req.getDeviceName())) {
            List<DeviceDO> deviceDOS = deviceService.getDeviceList(req.getDeviceName(), null, null);
            List<Long> deviceIds = deviceDOS.stream().map(DeviceDO::getId).collect(Collectors.toList());
            queryParams.setDeviceIds(deviceIds);
        }

        List<DeviceOpenRecordDO> openRecordDOS = this.service.findByModel(queryParams, start, pageSize, " gmt_created", " desc");
        List<Long> deviceIds = openRecordDOS.stream().map(DeviceOpenRecordDO::getDeviceId).collect(Collectors.toList());
        List<DeviceDO> devices = this.deviceService.getDevices(deviceIds, null, null, null);
        Map<Long, DeviceDO> deviceMap = devices.stream().collect(Collectors.toMap(DeviceDO::getId, Function.identity(), (a, b) -> a));
        openRecordDOS.forEach(f -> {
            if (deviceMap.containsKey(f.getDeviceId())) {
                f.setDeviceName(deviceMap.get(f.getDeviceId()).getDeviceName());
            }
        });
        return openRecordDOS;
    }

    public void exportOpenRecord(HttpServletResponse response, OpenRecordReq request, AbstractColumnWidthStyleStrategy customerConfig) {
        DeviceOpenRecordDO queryParams = this.converter.req2Do(request);
        List<DeviceOpenRecordDO> openRecordDOS = getDeviceOpenRecords(request, queryParams, CommonConstants.ZERO, Integer.MAX_VALUE);
        if (CollectionUtils.isEmpty(openRecordDOS)) {
            throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
        }
        if (openRecordDOS.size() > 50000) {
            throw new BizException(ErrorEnum.DATA_TO_MANY, String.format(ErrorEnum.DATA_TO_MANY.getMessage(), ", 目前暂支持导出50000行明细, 请缩短时间范围后重试"));
        }
        List<OpenRecordVO> records = openRecordDOS.stream().map(f -> this.converter.do2OpenRecordVo(f)).collect(Collectors.toList());
        try {
            ExcelUtil.setHeader(response, URLEncoder.encode("开门记录列表", "UTF-8"));
            // 执行导出
            ServletOutputStream outputStream = response.getOutputStream();
            EasyExcelFactory.write(outputStream, OpenRecordVO.class).sheet("开门记录列表").registerWriteHandler(customerConfig).doWrite(records);
        } catch (Exception e) {
            log.error("开门记录列表: {}", e.getMessage());
        }
    }

    public void addInfo(OpenCloseDTO openCloseWeightVO) {
        DeviceOpenRecordDO deviceOpenRecordDO = converter.vo2Do(openCloseWeightVO);
        deviceOpenRecordDO.setModifier(openCloseWeightVO.getOperatorInfo());
        deviceOpenRecordDO.setCreator(openCloseWeightVO.getOperatorInfo());
        service.add(deviceOpenRecordDO);
    }

    /**
     * 无重力柜子补货只有关门数据
     */
    public void openCloseAddInfo(OpenCloseDTO openCloseWeightVO) {
        DeviceOpenRecordDO deviceOpenRecordDO = converter.vo2Do(openCloseWeightVO);
        deviceOpenRecordDO.setGmtOpen(DateUtil.dateByStr(openCloseWeightVO.getRecordAt()));
        deviceOpenRecordDO.setGmtClose(DateUtil.dateByStr(openCloseWeightVO.getRecordAt()));
        deviceOpenRecordDO.setModifier(openCloseWeightVO.getOperatorInfo());
        deviceOpenRecordDO.setCreator(openCloseWeightVO.getOperatorInfo());
        service.add(deviceOpenRecordDO);
    }
    public void updateInfo(OpenCloseDTO openCloseWeightVO) {
        DeviceOpenRecordDO deviceOpenRecordDO = new DeviceOpenRecordDO();
        deviceOpenRecordDO.setId(openCloseWeightVO.getOpenRecordId());
        deviceOpenRecordDO.setGmtClose(DateUtil.dateByStr(openCloseWeightVO.getRecordAt()));
        deviceOpenRecordDO.setModifier(openCloseWeightVO.getOperatorInfo());
        service.update(deviceOpenRecordDO);

    }
//TODO
    public void warningEmail() {
        List<DeviceOpenRecordDO> deviceOpenRecord = service.findWarning();
        if (CollectionUtils.isEmpty(deviceOpenRecord)) {
            return;
        }
        List<MailDO> mailDOS = deviceOpenRecord.stream().map(f -> this.converter.do2DtoMail(f)).collect(Collectors.toList());
        List<Long> firmIds = deviceOpenRecord.stream().map(DeviceOpenRecordDO::getFirmId).filter(firmId -> !ObjectUtils.isEmpty(firmId)).collect(Collectors.toList());
        Map<Long, String> firmIdNameMap =new HashMap<>();
        if (firmIds.size() > 0) {
            firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);
        }
        Map<Long, String> finalFirmIdNameMap = firmIdNameMap;
        mailDOS.forEach(deviceOpenRecordDO -> deviceOpenRecordDO.setFirmName(finalFirmIdNameMap.get(deviceOpenRecordDO.getFirmId())));
        service.updateToSendEmailMark(deviceOpenRecord.stream().map(DeviceOpenRecordDO::getId).collect(Collectors.toList()));
    }
}

